These are 11 pages of 11 routines for handling numbers up to 32 bits in length. These routines are not commented, but they are easy to follow. Some of them require that you substitute in hexadecimal values for the opcodes and operands where the opcodes are using an address mode that is not supported by the 6502 and 6510 microprocessor.
The routines include:
ZeroRegs clear all GEOS registers
MoveLW moves a longword
MultLW multiplies two longwords
DivLW divides two longwords
AddLW adds two longwords
IncLW increments a longword
CmpLW compares two longwords
SubLW subtracts two longwords
DecLW decrements two longwords
Cmp1LW compares a longword to one
Cmp0LW compares a longword to zero
I will use the term "longword" when I am speaking of a register that is four bytes long. A one byte register is called a byte. A two byte register is called a word. I forget what a three byte register is called. And a four byte register is called a longword. If you really want to know what a three byte register is called, you can find the machine langauge book for the 68030 Motorola processor.
The routines are fully documented with instructions, and all routines necessary are included. If you have any problems, please notify me, and I will try to rectify whatever ails you, that is as long as the problem has something to do with these routines. :) (retarded smiley face)
You may notice that the divide and multiply routines are a little slow, especially when you are using very large values. The best solution to this problem is to multiply a large number by a small one, rather then a small value by a large value, since it will add the small value to itself very-large-value times.
The divide routine will check for division by 0, and check if operand1 is smaller than operand2, and will return somewhat correct values if either of these errors occur.
I worked on these for two days, so you better like them! Enjoy! :) (another retarded smiley face)
Nate Fiedler
Rd 3 Box 140
Bernville, PA 19506-9313
NateF on Q-Link
;DivLW - divide a 32 bit number by another 32 bit number
;Pass: x operand1 - zero page address of l
;DivLW - divide a 32 bit number by another 32 bit number
;Pass: x operand1 - zero page address of longword
; dividend
; y operand2 - zero page address of longword
; divisor
;Returns: x,y, word pointed to by x contains result of division
; r12 contains the remainder (longword value)
;Destroys: a, r11, r14-r15
;Note: DivLW will check for division by zero, and will
; exit with operand1 in remainder and operand1 will
; equal zero.
; If operand1 is less than operand2, it will exit with
; operand1 in remainder and operand1 will equal zero.
DivLW: sty r11L
stx r11H
LoadB r14L,0
sta r14H
sta r15L
sta r15H
ldx r11L
jsr Cmp0LW
beq 99$
ldx r11H
jsr CmpLW
bcc 99$
10$: jsr SubLW
ldx #r14
jsr IncLW
ldx r11H
jsr CmpLW
bcs 10$
99$: ldy #r12
ldx r11H
jsr MoveLW
ldy r11H
ldx #r14
jsr MoveLW
ldy r11L
ldx r11H
;IncLW - increment a longword value by one
;Pass: x operand1 - zero page address of longword
; to increment
;Return
;IncLW - increment a longword value by one
;Pass: x operand1 - zero page address of longword
; to increment
;Returns: x, value in register pointed to by x will be one
; greater than before call to IncLW.
; zero flag will be set or clear, to show if the value
; rolled from $FFFFFFFF to $00000000
;Destroys: nothing
IncLW: inc 0,x
bne 10$
inc 1,x
bne 10$
inc 2,x
bne 10$
inc 3,x
10$: rts
;CmpLW - compare two long words to each other
;CmpLW - compare two long words to each other
;Pass: x operand1 - zero page address of longword
; y operand2 - zero page address of other
; longword to compare operand1 to
;Destroys: a
;Returns: zero flag be set or clear
;Note: The "cmp zp,y" opcode will not work with
; geoAssembler version 1.0. Substitute in the hex value
; of this opcode with the absolute address of the
; operand and it will work.
; Example:
; .byte $d9,0,r1
; Will compare r1,y to value in "a" register
; This will make it use the absolute address mode.
; Note that the address is two bytes long.
;See
Commodore 64 Programmer's Reference Guide
for opcodes
;of this and all other machine language commands.
CmpLW: lda 3,x
cmp 3,y ; or .byte $d9,0,3
bne 10$
lda 2,x
cmp 2,y ; or .byte $d9,0,2
bne 10$
lda 1,x
cmp 1,y ; or .byte $d9,0,1
bne 10$
lda 0,x
cmp 0,y ; or .byte $d9,0,0
10$: rts
;SubLW - subtract two longword values
;Pass: x operand1 - zero page
;SubLW - subtract two longword values
;Pass: x operand1 - zero page address of longword
; destination register
operand2
- zero page address of longword
; value to subtract from operand1
;Returns: x,y, longword pointed to by x will contain result
; of subtraction.
operand1
operand1
operand2
;Destroys: a
;Note: The "sbc zp,y" opcode will not work with
; geoAssembler version 1.0. Substitute in the hex value
; of this opcode with the absolute address of the
; operand and it will work.
; Example:
; .byte $f9,0,r1
; Will subtract r1,y from value in "a" register
; This will make it use the absolute address mode.
; Note that the address is two bytes long.
;See
Commodore 64 Programmer's Reference Guide
for opcodes
;of this and all other machine language commands.
SubLW: sec
lda 0,x
sbc 0,y ; or .byte $f9,0,0
sta 0,x
lda 1,x
sbc 1,y ; or .byte $f9,0,1
sta 1,x
lda 2,x
sbc 2,y ; or .byte $f9,0,2
sta 2,x
lda 3,x
sbc 3,y ; or .byte $f9,0,3
sta 3,x
# # #"#
;DecLW - decrement a longword register by one
;Pass: x operand - zero page address of longword
; register to decrement
;Returns: x, word pointed to by x will be one less than before.
; Zero flag will be set or clear, to show if the value
; reached zero, but can be unreliable
;Destroys: a
DecLW: lda 0,x
bne 10$
lda 1,x
bne 20$
lda 2,x
bne 30$
lda 3,x
bne 40$
40$: dec 3,x
30$: dec 2,x
20$: dec 1,x
10$: dec 0,x
;Cmp1LW: -
;Cmp1LW: - compare a longword register to one
;Pass: x operand - zero page address of longword
; to compare to one
;Returns: zero flag set or clear
; After a call to Cmp1LW,
; a "beq" can be used to branch if value equaled one
; a "bne" can be used to branch if value did not
; equal one
;Destroys: a
Cmp1LW: lda 3,x
bne 10$
lda 2,x
bne 10$
lda 1,x
bne 10$
lda 0,x
cmp #1
10$: rts
;MultLW - multiply two 32 bit registers
;Pass:
;MultLW - multiply two 32 bit registers
;Pass: x operand1 - zero page address of longword
; multiplicand
; y operand2 - zero page address of longword
; multiplier
;Returns: x,y, register pointed to by x contains result,
; register pointed to by y will equal one
;Destroys: a, r12, r14-r15
;Note: operand1 maximum value can be $FFFF
; operand2 maximum value can be $7FFF
; Largest possible result will equal $7FFE8001
MultLW: sty r12L
stx r12H
ldx r12L
ldy r12H
jsr Cmp1LW
beq 99$
jsr Cmp0LW
bne 5$
jmp MoveLW
5$: ldy #r14
ldx r12H
jsr MoveLW
10$: ldx r12H
jsr AddLW
ldx r12L
jsr DecLW
jsr Cmp1LW
bne 10$
99$: ldy r12L
ldx r12H
;MoveLW - moves a 32 bit register to another
;MoveLW - moves a 32 bit register to another 32 bit register
;Pass: x operand1 - zero page address of source
; longword register
; y operand2 - zero page address of
; destination longword register
;Returns: x,y, register pointed to by y contains value in
; register pointed to by x
;Destroys: a
;Note: The "sta zp,y" opcode will not work with
; geoAssembler version 1.0. Substitute in the hex value
; of this opcode with the absolute address of the
; operand and it will work.
; Example:
; .byte $99,0,r1
; Will store accumulator to r1,y
; This will make it use the absolute address mode.
; Note that the address is two bytes long.
;See
Commodore 64 Programmer's Reference Guide
for opcodes
;of this and all other machine language commands.
MoveLW: lda 0,x
sta 0,y ; or .byte $99,0,0
lda 1,x
sta 1,y ; or .byte $99,0,1
lda 2,x
sta 2,y ; or .byte $99,0,2
lda 3,x
sta 3,y ; or .byte $99,0,3
;ZeroRegs - clears all GEOS regist
;ZeroRegs - clears all GEOS registers to zero
;Pass: nothing
;Returns: GEOS registers all equal zero
;Destroys: a,x, r0-r15
ZeroRegs: ldx #$1f
lda #0
10$: sta r0L,x
bpl 10$
;AddLW - add two 32 bit registers
;Pass: x operand1 - zero page address of longword
; destination
operand2
- zero page address of longword
; register to add to operand1
;Returns: x,y, word pointed to by x contains result of addition
operand1
operand1
operand2
;Destroys: a
;Note: The "adc zp,y" opcode will not work with
; geoAssembler version 1.0. Substitute in the hex value
; of this opcode with the absolute address of the
; operand and it will work.
; Example:
; .byte $79,0,r1
; Will adc r1,y with the value in the "a" register.
; This will make it use the absolute address mode.
; Note that the address is two bytes long.
;See
Commodore 64 Programmer's Reference Guide
for opcodes
;of this and all other machine language commands.
AddLW: clc
lda 0,x
adc 0,y ; or .byte $79,0,0
sta 0,x
lda 1,x
adc 1,y ; or .byte $79,0,1
sta 1,x
lda 2,x
adc 2,y ; or .byte $79,0,2
sta 2,x
lda 3,x
adc 3,y ; or .byte $79,0,3
sta 3,x
;Cmp0LW - compare 32 bit register to zero
;Pass: x operand - zero page address of longword
; to test
;Returns: zero flag either set or clear, depending on
;Cmp0LW - compare 32 bit register to zero
;Pass: x operand - zero page address of longword
; to test
;Returns: zero flag either set or clear, depending on result
;Destroys: a
;Description: Tests to see if a 32 bit register is equal
; to zero
; After calling Cmp0LW,
; a "beq" can be used to branch if it is equal to zero
; a "bne" can be used to branch if it is not equal